/*
 *  neuronspecs.h
 *  
 *
 *  Created by Jeff McKinstry on 7/15/09.
 *  Copyright 2009 The Neurosciences support corp. All rights reserved.
 *
 */
#ifndef NEURONSPECS_H
#define NEURONSPECS_H

#include <vector>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;



//*********************************************
template<typename T>
int find(T key, vector<T> array){
	
	int index = -1;
	for(int i = 0; i < array.size(); i++){
		if( array[i] == key ){
			index = i;
			break;
		}
	}
	return index;
	
	
}

//*********************************************
template<typename T>
void printvector(vector<T> v){
	
	for(int i = 0; i < v.size(); i++){
		cout << v[i] << " ";
	}
	cout << endl;
	
	
}




class neuronspecs {
public:

	

	neuronspecs(){  // By default.
		string initLayerNames[] =  {"L6", "L5", "L4", "L23", "L1", "Th", "RTN"};
		vector<string> v(initLayerNames,initLayerNames+7);
		layerNames = v;

	}
	
	
	// You can determine the number and names of the layers if you want.
	neuronspecs(vector<string> initLayerNames)
	: layerNames(initLayerNames)
	{
				
	}
	
//*************************
void read_neuronspecs(){

	Ntypes = 0;
	
	ifstream fin("neuronspecs.dat");
	
	string neuron_name;
	
	while ( fin >> neuron_name ){
		if( neuron_name[0] == '%' ) {
			string junk;
			getline(fin, junk); // ignore the rest of the line.
			cout << "comment line ignored: " << neuron_name << junk << endl;
			continue;
		}
		
		//cout << neuron_name;
		
		neuron_names.push_back(neuron_name);
		
		int tempi; 
		float tempf;
		double tempd;
		string temps;
		fin >> tempi;
		if( tempi < 0 ){
			cout << "Error reading neuronspecs.dat. Neuronal class number '" << tempi << "' was not recognized!" << endl; 
			exit(0);
		}
		class_number.push_back(tempi);

		fin >> tempi;
		if( tempi < 0 || tempi > 1 ){
			cout << "Error reading neuronspecs.dat. glutamatergic field must be 0 or 1; '" << tempi << "' was read!"<< endl; 
			exit(0);
		}
		glutamatergic.push_back(tempi);

		fin >> tempi; soma_layer.push_back(tempi);		
		fin >> tempf; C.push_back(tempf);
		fin >> tempf; K.push_back(tempf);
		fin >> tempf; vr.push_back(tempf);
		fin >> tempf; vt.push_back(tempf);
		fin >> tempf; vpeak_soma.push_back(tempf);
		fin >> tempf; vpeak_dendrite.push_back(tempf);
		fin >> tempf; G_up.push_back(tempf);
		fin >> tempf; G_down.push_back(tempf);
		fin >> tempf; a.push_back(tempf);
		fin >> tempf; b.push_back(tempf);
		fin >> tempf; c_soma.push_back(tempf);
		fin >> tempf; c_dendrite.push_back(tempf);
		fin >> tempf; d_soma.push_back(tempf);
		fin >> tempf; d_dend.push_back(tempf);
		fin >> tempf; U_upper_bound.push_back(tempf);
		fin >> tempf; background_Gexc.push_back(tempf);
		fin >> tempf; background_Ginh.push_back(tempf);
		fin >> tempf; decay_ampa.push_back( (1.0-1.0/tempf) );
		fin >> tempf; decay_nmda.push_back( (1.0-1.0/tempf) );
		fin >> tempf; decay_gabaa.push_back( (1.0-1.0/tempf) );
		fin >> tempf; decay_gabab.push_back( (1.0-1.0/tempf) );
		// added 6/1/11 AEK
		fin >> tempd; gabac_const.push_back(tempd);
		fin >> tempd; decay_gabac.push_back( (1.0-1.0/tempd) );
		fin >> tempi; gabac_start_msec.push_back(tempi);
		fin >> tempi; gabac_stop_msec.push_back(tempi);
		
		vector<float> tempvec(layerNames.size());
		for( int j = 0; j < layerNames.size();j++){
			fin >> tempf; tempvec[j] = tempf;
		}
		//printvector(tempvec);
		if( fin.eof() ){
			cout << " Error reading neuronspecs.dat.  Unexpected eof!" << endl;
			exit(0);
		}
		
		axon_spread.push_back(tempvec);
		
	}		
	
	Ntypes = neuron_names.size();
	cerr << "Ntypes read from file: " << Ntypes << endl;
		
}
	
	//************************
	vector<string> get_layer_names(){
		
		return layerNames;
	}
	
	//************************
	// Pre: read_neuronspecs() has been called.
	// Post: returns Ntypes that were in the neuronspec.dat file.
	int get_num_types(){
		
		return Ntypes;
		
	}
	
	
	//************************
	// Pre: read_neuronspecs() has been called.
	// Post: 
	vector<string> get_neuron_names(){
		
		return neuron_names;
		
	}

	
	//************************
	// Pre: read_neuronspecs() has been called.
	// Post: Isn't it obvious? 
	void get_all( vector<string> & out_neuron_names, 
				 vector<int> & out_class_number,
				 vector<int> & out_glutamatergic,
				 vector<int> & out_soma_layer,
				 vector<float> & out_C,
				 vector<float> & out_K,
				 vector<float> & out_vr, 
				 vector<float> & out_vt,
				 vector<float> & out_vpeak_soma,
				 vector<float> & out_vpeak_dendrite,
				 vector<float> & out_G_up,
				 vector<float> & out_G_down,
				 vector<float> & out_a,
				 vector<float> & out_b,
				 vector<float> & out_c_soma,
				 vector<float> & out_c_dendrite,
				 vector<float> & out_d_soma,
				 vector<float> & out_d_dend,
				 vector<float> & out_U_upper_bound,
				 vector<float> & out_background_Gexc,
				 vector<float> & out_background_Ginh,
				 vector<float> & out_decay_ampa,
				 vector<float> & out_decay_nmda,
				 vector<float> & out_decay_gabaa,
				 vector<float> & out_decay_gabab,
				 vector< vector<float> > & out_axon_spread,
				 vector<double> & out_gabac_const,
				 vector<double> & out_decay_gabac,
				 vector<int> & out_gabac_start_msec,
				 vector<int> & out_gabac_stop_msec
	){
		
		out_neuron_names = neuron_names; 
		out_class_number = class_number;
		out_glutamatergic = glutamatergic;
		out_soma_layer = soma_layer;
		out_C = C;
		out_K = K;
		out_vr = vr; 
		out_vt = vt;
		out_vpeak_soma = vpeak_soma;
		out_vpeak_dendrite = vpeak_dendrite;
		out_G_up = G_up;
		out_G_down = G_down;
		out_a = a;
		out_b = b;
		out_c_soma = c_soma;
		out_c_dendrite = c_dendrite;
		out_d_soma = d_soma;
		out_d_dend = d_dend;
		out_U_upper_bound = U_upper_bound;
		out_background_Gexc = background_Gexc;
		out_background_Ginh = background_Ginh;
		out_decay_ampa = decay_ampa;
		out_decay_nmda = decay_nmda;
		out_decay_gabaa = decay_gabaa;
		out_decay_gabab = decay_gabab;
		out_axon_spread = axon_spread;
		// added 6/1/11 AEK
		out_gabac_const = gabac_const;
		out_decay_gabac = decay_gabac;
		out_gabac_start_msec = gabac_start_msec;
		out_gabac_stop_msec = gabac_stop_msec;
		
	}
	

private:
	
	vector<string> layerNames;
	int Ntypes;
	vector<string> neuron_names;
	
	vector<int> class_number;
	vector<int> glutamatergic;
	vector<int> soma_layer;  // 1-6 for cortex anatomical layer; 7 for thalamus.
	vector<float> C;
	vector<float> K;	
	vector<float> vr; 
	vector<float> vt;
	vector<float> vpeak_soma;
	vector<float> vpeak_dendrite;
	vector<float> G_up;
	vector<float> G_down;
	vector<float> a;
	vector<float> b;
	vector<float> c_soma;
	vector<float> c_dendrite;
	vector<float> d_soma;
	vector<float> d_dend;
	vector<float> U_upper_bound;
	vector<float> background_Gexc;
	vector<float> background_Ginh;
	vector<float> decay_ampa;
	vector<float> decay_nmda;
	vector<float> decay_gabaa;
	vector<float> decay_gabab;
	vector< vector<float> > axon_spread;
	// added 6/1/11 AEK
	vector<double> gabac_const;
	vector<double> decay_gabac;
	vector<int> gabac_start_msec;
	vector<int> gabac_stop_msec;
		
	
};
			
#endif
